package com.bootdo.staticmask.controller;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;

import com.bootdo.common.utils.FileUtil;
import com.bootdo.staticmask.domain.MaskRuleDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.bootdo.common.utils.R;
import com.bootdo.staticmask.core.bean.ColumnProperty;
import com.bootdo.staticmask.core.bean.OriDataSource;
import com.bootdo.staticmask.core.bean.TableProperty;
import com.bootdo.staticmask.core.mask.MaskMain;
import com.bootdo.staticmask.dao.MaskFileDao;
import com.bootdo.staticmask.dao.MaskJobDao;
import com.bootdo.staticmask.dao.MaskOracleDao;
import com.bootdo.staticmask.domain.MaskFileDO;
import com.bootdo.staticmask.domain.MaskJobModel;
import com.bootdo.staticmask.domain.MaskOracleDO;
import com.bootdo.staticmask.service.MaskOracleService;

/**
 * Created by lkg on 2018/4/26
 */
@Controller
@RequestMapping("/staticmask/mask")
public class MaskController {
	private final MaskFileDao maskFileDao;
	private final MaskOracleDao maskOracleDao;
	private final MaskOracleService maskOracleService;
	private final MaskJobDao maskJobDao;

	@Value("${staticMask.result.path}")
	private String resultPath;

	@Autowired
	public MaskController(MaskFileDao maskFileDao, MaskOracleDao maskOracleDao, MaskOracleService maskOracleService, MaskJobDao maskJobDao) {
		this.maskFileDao = maskFileDao;
		this.maskOracleDao = maskOracleDao;
		this.maskOracleService = maskOracleService;
		this.maskJobDao = maskJobDao;
	}

	@ResponseBody
	@PostMapping("/start-job")
	public R startJob(@RequestBody MaskJobModel maskJobModel) {
		boolean isnotMask = false;
		List<TableProperty> tablePropertyList = maskJobModel.getTable();
		for (TableProperty tableProperty: tablePropertyList){
			List<ColumnProperty> columnPropertyList = tableProperty.getColumnPropertyList();
			for (ColumnProperty columnProperty: columnPropertyList){
				MaskRuleDO maskRuleDO = columnProperty.getMaskRuleDO();
				if (maskRuleDO != null){
					isnotMask = true;
					break;
				}
			}
		}
		if (!isnotMask){
			return R.error("请选择脱敏规则");
		}
		if (!resultPath.endsWith(File.separator)) {
			resultPath += File.separator;
		}

		String category = maskJobModel.getCategory();
		int dataSourceId = maskJobModel.getDataSource();
//		List<TableProperty> tablePropertyList = maskJobModel.getTable();

		OriDataSource<?> oriDataSource;
		if ("CSV".equals(category) || "TXT".equals(category)) {
			MaskFileDO maskFile = maskFileDao.get(dataSourceId);
			if (maskFile == null) {
				return R.error("数据源已被修改，任务提交失败");
			}else if (!maskFile.getCreatetime().equals(maskJobModel.getDataSourceLastChangeTime())) {
				return R.error("数据源 " + maskFile.getFileName() + " 已被修改，任务提交失败");
			}
			oriDataSource = new OriDataSource<>(maskFile, tablePropertyList);
		} else if ("ORACLE".equals(category)) {
			MaskOracleDO oracleDO = maskOracleDao.get(dataSourceId);
			if (oracleDO == null) {
				return R.error("数据源 已被修改，任务提交失败");
			}else if ( !oracleDO.getCreatetime().equals(maskJobModel.getDataSourceLastChangeTime())) {
				return R.error("数据源 " + oracleDO.getOracleName() + " 已被修改，任务提交失败");
			}
			oriDataSource = new OriDataSource<>(oracleDO, tablePropertyList);
		} else {
			return R.error("数据源错误");
		}

		MaskMain maskMain = new MaskMain(oriDataSource, resultPath, maskJobDao);
		maskMain.mask();
		return R.ok();
	}

	@ResponseBody
	@GetMapping({ "/columnProperty/{category}/{id}/{tableName}", "/columnProperty/{category}/{id}" })
	public List<ColumnProperty> getline(@PathVariable String category, @PathVariable Integer id,
			@PathVariable(required = false) String tableName) {
		List<ColumnProperty> columnPropertyList = new ArrayList<>();
		if ("ORACLE".equals(category)) {
			// 选择数据库表后会返回表里的列信息
			String[] tableInfo = tableName.split("-");
			return maskOracleService.getColumns(id, tableInfo[0], tableInfo[1]);
		} else if ("CSV".equals(category) || "TXT".equals(category)) {
			String table = tableName.replace("-",".");
			MaskFileDO maskFile = maskFileDao.get(id);
			File file = new File(maskFile.getFilePath());
			if (file.isDirectory()){
				List<File> fileList = FileUtil.getFileList(file);
				for (File f: fileList){
					if (f.getName().equals(table)){
						columnPropertyList.addAll(textFirstLine(f.getAbsolutePath(), maskFile.getFileEncode()
								, maskFile.getTextQualifier()+maskFile.getFileDelimeter()+maskFile.getTextQualifier()));
					}
				}
			}else {
				columnPropertyList.addAll(textFirstLine(file.getAbsolutePath(), maskFile.getFileEncode()
						, maskFile.getTextQualifier()+maskFile.getFileDelimeter()+maskFile.getTextQualifier()));
			}
		}
		return columnPropertyList;
	}

	@ResponseBody
	@GetMapping("tableProperty/{category}/{id}")
	public List<Map<String, String>> getTable(@PathVariable String category, @PathVariable Integer id){
		List<Map<String, String>> tables = null;
		if ("ORACLE".equals(category)) {
			tables = maskOracleService.getTables(id);
		}else if ("CSV".equals(category) || "TXT".equals(category)) {
			tables = new ArrayList<>();
			MaskFileDO maskFileDO = maskFileDao.get(id);
			String filePath = maskFileDO.getFilePath();
			File file = new File(filePath);
			if (file.isDirectory()){
				for (File f: FileUtil.getFileList(file)){
					HashMap<String, String> hashMap = new HashMap<>();
					hashMap.put("name", f.getName());
					hashMap.put("comment", "");
					tables.add(hashMap);
				}
			}else {
				String tableName = filePath.substring(filePath.lastIndexOf(File.separatorChar) + 1);
				HashMap<String, String> hashMap = new HashMap<>();
				hashMap.put("name", tableName);
				hashMap.put("comment", "");
				tables.add(hashMap);
			}
		}
		return tables;
	}

	@ResponseBody
	@GetMapping("/dataSource/{category}")
	public List<Map<String, Object>> getDataSource(@PathVariable String category) {
		if ("ORACLE".equals(category)) {
			return maskOracleDao.findNameAndIdAndCreatetime();
		} else if ("CSV".equals(category) || "TXT".equals(category)) {
			return maskFileDao.findNameAndIdAndCreatetime(category);
		}
		return null;
	}


	/**
	 * 文本数据获取第一行数据
	 * @param filePath 文本路径
	 * @param encode 编码格式
	 * @param delimeter 分隔符
	 * @return List<ColumnProperty>
	 */
	private List<ColumnProperty> textFirstLine(String filePath, String encode, String delimeter){
		List<ColumnProperty> columnPropertyList = new ArrayList<>();
		Path path = Paths.get(filePath);
		Charset cs = Charset.forName(encode);
		try {
			Stream<String> lines = Files.lines(path, cs);
			Optional<String> str = lines.findFirst();
			String firstLine;
			if (delimeter.length() == 1){
				firstLine = str.get();
			}else {
				firstLine = str.get().substring(1,str.get().length()-1);
			}
			String[] strArry = firstLine.split(delimeter);
			int i = 0;
			for (String s : strArry) {
				ColumnProperty c = new ColumnProperty();
				c.setId(i++);
				c.setColumnName(s);
				c.setColumnDataType("String");
				c.setColumnComment("-");
				columnPropertyList.add(c);
			}
		} catch (IOException | UncheckedIOException e) {
			e.printStackTrace();
			return null;
		}
		return columnPropertyList;
	}


}
